package org.easy.eao.spring;

import java.lang.annotation.Annotation;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import org.easy.eao.Action;
import org.easy.eao.EaoBuilder;
import org.easy.eao.utils.ActionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;

/**
 * Spring 的 EAO 接口 工厂模板
 * 
 * @author Frank
 */
@SuppressWarnings({ "unchecked", "rawtypes" })
public class SpringEaoFactory implements FactoryBean, BeanFactoryAware, InitializingBean {

	/** 日志对象 */
	static final Logger logger = LoggerFactory.getLogger(SpringEaoFactory.class);
	
	public static final String ATTRIBUTE_ACTIONS = "actions";
	public static final String ATTRIBUTE_CLAZZ = "clazz";
	public static final String ATTRIBUTE_DEFAULT_ACTIONS_NAME = "defaultActionsName";
	
	/** 默认 EAO 创建器的标识 */
	public static final String DEFAULT_EAO_BUILDER_NAME = "default_eaoBuilder";
	/** 默认的动作集合标识 */
	public static final String DEFAULT_ACTIONS_NAME = "default_actions";

	/** EAO 接口的类型 */
	private Class<?> clazz;
	/** EAO 创建器 */
	private EaoBuilder builder;
	/** 强制指定的 Action 动作类集合 */
	private Set<Class<Action<?>>> actions;
	/** 默认 Action 集合名 */
	private String defaultActionsName;
	/** Spring 的 BeanFactory */
	private BeanFactory beanFactory;
	
	private Object eao;

	@Override
	public Object getObject() throws Exception {
		return eao;
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		if (clazz == null) {
			String message = "必须要指定 EAO 接口类型(clazz)";
			logger.error(message);
			throw new IllegalArgumentException(message);
		}
		if (builder == null) {
			logger.debug("没指定 EaoBuilder 以默认 EaoBuilder 替代");
			builder = (EaoBuilder) beanFactory.getBean(DEFAULT_EAO_BUILDER_NAME);
		}
		if (defaultActionsName == null) {
			logger.debug("没指定存取动作集合，以默认存取动作集合替代");
			defaultActionsName = DEFAULT_ACTIONS_NAME;
		}
		Set<Class<Action<?>>> defaults = (Set<Class<Action<?>>>) beanFactory.getBean(DEFAULT_ACTIONS_NAME);
		actions = getFinalActionSet(defaults, actions);
		logger.debug("开始创建 EAO 类实例...");
		eao = getBuilder().builder(clazz, actions);
	}
	
	private Set<Class<Action<?>>> getFinalActionSet(Set<Class<Action<?>>> defaults, 
			Set<Class<Action<?>>> overwrites) throws InstantiationException, IllegalAccessException {
		Map<Class<? extends Annotation>, Class<Action<?>>> actions = 
			ActionUtils.toMap(defaults);
		Map<Class<? extends Annotation>, Class<Action<?>>> others = 
			ActionUtils.toMap(overwrites);
		for (Entry<Class<? extends Annotation>, Class<Action<?>>> entry : others.entrySet()) {
			actions.put(entry.getKey(), entry.getValue());
		}
		return new HashSet<Class<Action<?>>>(actions.values());
	}

	// BeanFactoryAware's Method
	
	@Override
	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
		this.beanFactory = beanFactory;
	}

	// FactoryBean's Method

	@Override
	public Class<?> getObjectType() {
		return clazz;
	}

	@Override
	public boolean isSingleton() {
		return true;
	}

	// Default Getter and Setter ...

	public Class<?> getClazz() {
		return clazz;
	}

	public void setClazz(Class<?> clazz) {
		this.clazz = clazz;
	}

	public void setBuilder(EaoBuilder builder) {
		this.builder = builder;
	}
	
	public EaoBuilder getBuilder() {
		return builder;
	}
	
	public Set<Class<Action<?>>> getActions() {
		return actions;
	}

	public void setActions(Set<Class<Action<?>>> actions) {
		this.actions = actions;
	}

	public void setDefaultActionsName(String defaultActionsName) {
		this.defaultActionsName = defaultActionsName;
	}

}
